<template>
	<div class="dt-upload-image">
		<div class="image-box" @click="showDialog=true" :style="'width:'+boxwh+'px;height:'+boxwh+'px;'">
			<img v-if="imgSrc" :src="imgSrc" />
			<i v-else-if="!uploadFlag" class="el-icon-plus"></i>
			<el-progress v-if="uploadFlag" type="circle"
				:width="boxwh-22"
				:height="boxwh-22"
				:percentage="uploadPercent">
			</el-progress>
		</div>
		<el-dialog :title="title" :visible.sync="showDialog" :fullscreen="fullDialog" append-to-body>
			<div class="cropper-wrap">
				<div class="canvas-box">
					<div v-if="imgSrc&&!options.imgSource" class="img-box">
						<img :src="imgSrc" />
					</div>
					<vue-cropper v-else ref="cropper"
						:info="true"
						:full="true"
						:infoTrue="true"
						:img="options.imgSource"
						:outputSize="options.outputSize"
						:output-type="options.outputType"
						:fixed="options.fixed"
						:fixedNumber="options.fixedNumber"
						:fillColor="options.fillColor">
					</vue-cropper>
				</div>
				<div class="btns-box">
					<div class="list-box">
						<el-button-group>
							<el-button icon="el-icon-crop" :disabled="!options.imgSource" @click="cropStart"></el-button>
							<el-button icon="el-icon-rank" :disabled="!options.imgSource" @click="cropStop"></el-button>
							<el-button icon="el-icon-refresh-left" :disabled="!options.imgSource" @click="cropRotateLeft"></el-button>
							<el-button icon="el-icon-refresh-right" :disabled="!options.imgSource" @click="cropRotateRight"></el-button>
							<el-button icon="el-icon-plus" :disabled="!options.imgSource" @click="cropChangeScale(1)"></el-button>
							<el-button icon="el-icon-minus" :disabled="!options.imgSource" @click="cropChangeScale(-1)"></el-button>
						</el-button-group>
						<el-select v-model="options.fixedSelect"
							:disabled="!options.imgSource"
							placeholder="截图比例"
							@change="cropFixedNumber"
							clearable>
							<el-option label="1：1" :value="[1,1]"></el-option>
							<el-option label="4：3" :value="[4,3]"></el-option>
							<el-option label="3：4" :value="[3,4]"></el-option>
							<el-option label="16：9" :value="[16,9]"></el-option>
							<el-option label="9：16" :value="[9,16]"></el-option>
						</el-select>
					</div>
					<div class="list-box">
						<el-upload ref="upload" accept="image/*"
							:disabled="uploadFlag"
							:action="action"
							:show-file-list="false"
							:auto-upload="false"
							:http-request="handleSourceUpload"
							:on-change="handleChange"
							:on-error="handleError">
							<el-button icon="el-icon-folder-opened">浏览..</el-button>
						</el-upload>
						<el-input placeholder="请输入图片网址" v-model="options.imgUri" clearable>
							<template slot="prepend">
								<el-select v-model="options.remoteType">
									<el-option label="普通加载" :value="0"></el-option>
									<el-option label="服务器代理" :value="1"></el-option>
								</el-select>
							</template>
							<el-button slot="append" icon="el-icon-upload" @click="cropLoadRemote">载入</el-button>
						</el-input>
					</div>
				</div>
			</div>
			<div slot="footer" class="dialog-footer">
				<el-button type="primary" @click="handleCropUpload" :disabled="uploadFlag">上传截图</el-button>
				<el-button type="success" @click="submitSourceUpload" :disabled="uploadFlag">上传原图</el-button>
				<el-button @click="showDialog=false">取消</el-button>
			</div>
		</el-dialog>
	</div>
</template>

<script>
	import { VueCropper } from 'vue-cropper'
	
	/* 
	 * 图片上传组件
	 * value 绑定的值
	 */
	export default {
		name: 'DtUploadImage',
		components: {
			VueCropper,
		},
		props: {
			value: {
				type: String,
				default: null,
			},
			action: {
				type: String,
				default: '/upload',
			},
			size: {
				type: Number,
				default: 5120,
			},
			title: {
				type: String,
				default: '上传图片',
			},
			boxwh: {
				type: Number,
				default: 98,
			}
		},
		data() {
			return {
				showDialog: false,
				fullDialog: false,
				imgSrc: '',
				uploadFlag: false,
				uploadPercent: 0,
				options: {
					remoteType: 0, // 远程代理
					imgUri: '', // 远程文件网址
					imgSource: '', // 画布图片地址
					fixed: false, // 是否开启截图框宽高固定比例
					fixedSelect: '', //选择框选中的值，分开绑定
					fixedNumber: [1,1], // 截图框的宽高比例, 开启fixed生效
					fillColor: '#ffffff', //导出时背景颜色填充
					outputType: 'webp', // jpeg, png, webp
					outputSize: 0.8, // 裁剪生成图片的质量0.1-1
				}
			}
		},
		methods: {
			//选取前检查
			handleBefore(file) {
				const isImg = /^image\/\w+$/i.test(file.type)
				if (!isImg) {
					this.$message.error('只能上传图片文件')
					return false
				}
				return true;
			},
			//选取图片后
			handleChange(file) {
				const isImg = /^image\/\w+$/i.test(file.raw.type)
				if (!isImg) {
					this.$message.error('只能上传 JPG、PNG、GIF、WEBP格式')
					return false
				}
				let fileSize = parseFloat(file.size / 1024);//字节转为KB
				if (fileSize > this.size) {
					this.$message.error(`图片大小不能超过${this.size}KB`);
					return false;
				}
				this.options.imgSource = URL.createObjectURL(file.raw);
				this.options.imgUri = '' //清空远程图片URL
			},
			//上传裁剪图片
			handleCropUpload() {
				let _this = this;
				//检查是否有上传文件
				if(!_this.options.imgSource) {
					_this.$message.error('错误提示：没有找到上传文件');
					return;
				}
				//关闭Dialog窗体
				_this.showDialog = false
				//开始上传
				_this.$refs.cropper.getCropBlob((data) => {
					const formData = new FormData();
					formData.append("file", data);
					_this.$api.request({
						method: 'file',
						url: `${_this.action}`,
						data: formData,
						progress(event) {
							_this.handleProcess(event);
						},
						success(res) {
							_this.options.imgSource = '' // 请空文件
							_this.handleSuccess(res.data)
						},
						error() {
							_this.$refs.upload.clearFiles() //清空上传控制文件列表
							_this.uploadFlag = false;
						}
					})
				})
			},
			//上传原图
			handleSourceUpload(data) {
				let _this = this;
				const formData = new FormData();
				formData.append("file", data.file);
				_this.$api.request({
					method: 'file',
					url: `${_this.action}`,
					data: formData,
					progress(event) {
						_this.handleProcess(event);
					},
					success(res) {
						_this.options.imgSource = '' // 请空文件
						_this.handleSuccess(res.data)
					},
					error() {
						_this.uploadFlag = false;
						_this.$refs.upload.clearFiles() //清空上传控制文件列表
					}
				})
			},
			//上传成功
			handleSuccess(data) {
				this.uploadFlag = false;
				this.uploadPercent = 0;
				//拼接得到图片url
				const imageUrl = data[0].filePath;
				this.imgSrc = this.$api.loadFile(imageUrl);
				//触发事件 input，父组件会修改绑定的 value 值
				this.$emit('input', imageUrl);
			},
			//上传进度
			handleProcess(event) {
				this.uploadFlag = true;
				this.uploadPercent = Math.abs((event.loaded / event.total * 100).toFixed(0));
			},
			//上传出错时
			handleError(err) {
				console.log('上传出错：'+err)
			},
			//启用裁剪功能
			cropStart() {
				if(!this.options.imgSource) return
				this.$refs.cropper.startCrop()
			},
			//取消裁剪
			cropStop() {
				if(!this.options.imgSource) return
				this.$refs.cropper.stopCrop()
			},
			//图片左旋转
			cropRotateLeft() {
				if(!this.options.imgSource) return
				this.$refs.cropper.rotateLeft();
			},
			//图片右旋转
			cropRotateRight() {
				if(!this.options.imgSource) return
				this.$refs.cropper.rotateRight();
			},
			//图片缩放
			cropChangeScale(num) {
				if(!this.options.imgSource) return
				this.$refs.cropper.changeScale(num)
			},
			//图片比例
			cropFixedNumber(){
				let _this = this;
				//清除截图
				_this.$refs.cropper.clearCrop()
				//检查是否没有选中值
				if(!!_this.options.fixedSelect) {
					// 开启比例
					if(!_this.options.fixed) _this.options.fixed = true;
					// 设置比例值
					_this.options.fixedNumber = _this.options.fixedSelect
				} else {
					//关闭比例
					_this.options.fixed = false;
				}
			},
			//载入远程图片
			cropLoadRemote(){
				let _this = this
				if(!_this.options.imgUri) return
				let uriSource = _this.options.imgUri.trim();
				if(_this.options.remoteType == 1){
					//请求服务器获取图片
					_this.$api.request({
						url: `/upload/remote?uri=${encodeURIComponent(uriSource)}`,
						success(res) {
							_this.options.imgSource = res.data
						}
					})
				} else {
					//不使用代理直接赋值
					_this.options.imgSource = uriSource
				}
			},
			//提交原图上传
			submitSourceUpload() {
				let _this = this
				//检查远程图片URL，如果非空则直接赋值地址
				if(!!_this.options.imgUri) {
					//检查是否有上传文件
					if(!_this.options.imgUri.startsWith("http")) {
						_this.$message.error('错误提示：图片的URL格式有误');
						return;
					}
					_this.showDialog = false //关闭Dialog
					//触发事件 input，父组件会修改绑定的 value 值
					_this.$emit('input', _this.options.imgUri)
					return
				}
				//检查是否有上传文件
				if(!_this.options.imgSource) {
					_this.$message.error('错误提示：没有找到上传文件');
					return;
				}
				//关闭Dialog窗体
				_this.showDialog = false
				//否则使用上传控制
				_this.$refs.upload.submit();
			},
		},
		mounted() {
			//如果页面宽度小于600则全屏Dialog
			if(window.innerWidth < 600) this.fullDialog = true
		},
		watch: {
			value: {
				immediate: true,
				handler(newVal) {
					if(!newVal) return
					this.imgSrc = this.$api.loadFile(newVal)
				}
			},
		},
	}
</script>

<style lang="scss">
	.image-box {
		display: flex;
		justify-content: center;
		align-items: center;
		border: 1px dashed #d9d9d9;
		border-radius: 6px;
		box-sizing: border-box;
		cursor: pointer;
		&>i {
			font-size: 28px;
		}
		&>img {
			margin: auto;
			max-width: 100%;
			max-height: 100%
		}
		.el-progress{
			position: absolute;
			top: 0;
			left: 0;
			margin: 10px;
		}
	}
	.cropper-wrap {
		position: relative;
		margin: -20px 0;
		.canvas-box {
			width: 100%;
			height: 35vh;
			.img-box {
				display: flex;
				justify-content: center;
				align-items: center;
				width: 100%;
				height: 100%;
				box-sizing: border-box;
				border: 1px solid #E4E7ED;
				border-radius: 4px;
				&>img {
					margin: auto;
					max-width: 100%;
					max-height: 100%
				}
			}
		}

		.btns-box {
			.list-box {
				display: flex;
				justify-content: space-between;
				margin: 10px -5px 0 -5px;
				&> div {
					margin: 0 5px;
					&:first-child {
						flex-shrink: 0;
					}
					&:last-child {
						flex-grow: 1;
					}
				}
			}
		}
	}
</style>